package cn.com.bluemoon.daps.standard.service.impl;

import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.result.ExcelImportResult;
import cn.com.bluemoon.common.security.BmDapConfig;
import cn.com.bluemoon.daps.api.sys.RemoteSysDeptService;
import cn.com.bluemoon.daps.api.sys.RemoteSystemInfoService;
import cn.com.bluemoon.daps.common.constant.DapConstant;
import cn.com.bluemoon.daps.common.domain.ResultBean;
import cn.com.bluemoon.daps.common.domain.UserInfoHolder;
import cn.com.bluemoon.daps.common.enums.BmStatus;
import cn.com.bluemoon.daps.common.enums.ReferRulesType;
import cn.com.bluemoon.daps.common.enums.StandardAuditStatus;
import cn.com.bluemoon.daps.common.enums.StandardDataType;
import cn.com.bluemoon.daps.common.exception.DapException;
import cn.com.bluemoon.daps.common.exception.DapThrowException;
import cn.com.bluemoon.daps.common.toolkit.BmAssetUtils;
import cn.com.bluemoon.daps.standard.client.DapModelModuleFacade;
import cn.com.bluemoon.daps.standard.client.DapSystemModuleFacade;
import cn.com.bluemoon.daps.standard.common.excel.ExcelProperty;
import cn.com.bluemoon.daps.standard.common.excel.IndexStandardDataVo;
import cn.com.bluemoon.daps.standard.dto.ExcelImportGroup;
import cn.com.bluemoon.daps.standard.entity.*;
import cn.com.bluemoon.daps.standard.excel.ExcelImportResultUtils;
import cn.com.bluemoon.daps.standard.excel.easypoi.IndStdImportVerifyHandler;
import cn.com.bluemoon.daps.standard.service.*;
import cn.com.bluemoon.daps.standard.vo.*;
import cn.com.bluemoon.daps.system.entity.DapSystemInfo;
import cn.com.bluemoon.daps.system.vo.BizLineResponseVo;
import cn.com.bluemoon.daps.system.vo.DapSystemWechatDeptTreeVo;
import cn.hutool.core.text.StrFormatter;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRElt;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import reactor.util.function.Tuple2;

import javax.annotation.Resource;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author Jarod.Kong
 */
@Service
@Transactional(rollbackFor = {DapException.class, RuntimeException.class})
@Slf4j
public class DapStandardModifyServiceImpl implements DapStandardModifyService {
    @Resource
    private DapSystemCategoryService dapSystemCategoryService;
    @Resource
    private RemoteSysDeptService systemDepartmentService;
    @Resource
    private DapSystemModuleFacade dapSystemModuleFacade;

    @Resource
    private DapStandardDimService dimService;

    @Autowired
    private DapStandardBasicService dapStandardBasicService;
    @Autowired
    private DapStandardBasicDicService dapStandardBasicDicService;
    @Resource
    private DapStandardIndexService dapStandardIndexService;
    @Resource
    private DapStandardAuditVersionMainService auditVersionMainService;
    @Resource
    private RemoteSystemInfoService systemInfoService;

    @Autowired
    private DapStandardIndexService standardIndexService;

    @Autowired
    private DapSystemSequenceGenerateService sequenceGenerateService;

    @Autowired
    private DapModelModuleFacade modelModuleFacade;

    @Resource
    private BmDapConfig bmDapConfig;

    private static String formatSheetErrorInfo(String error1, String standardImportFileSheet1Name, int size, int size2) {
//        , (StringUtils.isBlank(error1) ? "" : "原因是:" + error1)
        return String.format("%s导入%d条，失败%d条", standardImportFileSheet1Name, size, size2);
    }

    /**
     * 根据读取Excel的每个sheet进行生成导入结果
     * <p>
     * 数据标准导入{}条，失败{}条，详情：
     * notnull: 基础代码标准导入{}条，失败{}条
     * notnull: 基础代码值导入{}条，失败{}条
     */
    private static ResultBean<?> resultOf(ExcelImportResult<BasicStandardAndDicVo> basicStandardExcelImportResult,
                                          ExcelImportResult<BasicStandardAndDicMiddleVo> basicStandardAndDicMiddleExcelImportResult,
                                          ExcelImportResult<DapStandardBasicDic> basicStandardDicExcelImportResult) {
        ImmutableMap.Builder<String, Object> resultMap = ImmutableMap.<String, Object>builder();
        if (basicStandardExcelImportResult != null) {
            String error1 = ExcelImportResultUtils.generateSheetErrorInfoByFailList(basicStandardExcelImportResult.getFailList());
            resultMap.put(DapConstant.DapStandard.FILE_SHEET_TOTAL, basicStandardExcelImportResult.getList().size())
                    .put(DapConstant.DapStandard.STANDARD_IMPORT_FILE_SHEET1_NAME, formatSheetErrorInfo(error1, DapConstant.DapStandard.STANDARD_IMPORT_FILE_SHEET1_NAME, basicStandardExcelImportResult.getList().size(), basicStandardExcelImportResult.getFailList().size()))
                    .put(DapConstant.DapStandard.STANDARD_IMPORT_FILE_SHEET1_NAME_DETAIL, basicStandardExcelImportResult.getFailList());
        }
        if (basicStandardAndDicMiddleExcelImportResult != null) {
            String error2 = ExcelImportResultUtils.generateSheetErrorInfoByFailList(basicStandardAndDicMiddleExcelImportResult.getFailList());
            String sheet2Msg = formatSheetErrorInfo(error2, DapConstant.DapStandard.STANDARD_IMPORT_FILE_SHEET2_NAME, basicStandardAndDicMiddleExcelImportResult.getList().size(), basicStandardAndDicMiddleExcelImportResult.getFailList().size());
            resultMap.put(DapConstant.DapStandard.STANDARD_IMPORT_FILE_SHEET2_NAME, sheet2Msg)
                    .put(DapConstant.DapStandard.STANDARD_IMPORT_FILE_SHEET2_NAME_DETAIL, basicStandardAndDicMiddleExcelImportResult.getFailList());
        }
        if (basicStandardDicExcelImportResult != null) {
            String error3 = ExcelImportResultUtils.generateSheetErrorInfoByFailList(basicStandardDicExcelImportResult.getFailList());
            String sheet3Msg = formatSheetErrorInfo(error3, DapConstant.DapStandard.STANDARD_IMPORT_FILE_SHEET3_NAME, basicStandardDicExcelImportResult.getList().size(), basicStandardDicExcelImportResult.getFailList().size());
            resultMap.put(DapConstant.DapStandard.STANDARD_IMPORT_FILE_SHEET3_NAME, sheet3Msg)
                    .put(DapConstant.DapStandard.STANDARD_IMPORT_FILE_SHEET3_NAME_DETAIL, basicStandardDicExcelImportResult.getFailList());
        }
        return ResultBean.ok(resultMap.build());
    }

    @Override
    public Optional<String> saveStandardBasicAndDic(BasicStandardAndDicVo basicStandardAndDicVo) {
        // check 标准数据中是否已存在，如果存在则，不允许增加
        basicStandardAndDicVo = dapStandardBasicService.checkAndThenSaveOrUpdate(basicStandardAndDicVo);
        String standardId = basicStandardAndDicVo.getId();
        // 针对代码类增加字典
        List<DapStandardBasicDic> basicDics = basicStandardAndDicVo.getDapStandardBasicDics();
        dapStandardBasicDicService.mySaveOrUpdateBatch(basicStandardAndDicVo, basicDics, standardId);
        return Optional.ofNullable(standardId);
    }

    /**
     * 系统新增保存
     */
    @Override
    public String saveStandardBasicAndDicAndAudit(BasicStandardAndDicVo basicStandardAndDicVo) {
        return saveOrUpdateStandardAndAudit(basicStandardAndDicVo, null, null);
    }

    /**
     * 针对导入中 指定审批状态为待审批
     */
    @Override
    public String saveStandardBasicAndDicAndAudit(BasicStandardAndDicVo basicStandardAndDicVo, StandardAuditStatus auditStatus) {
        return saveOrUpdateStandardAndAudit(basicStandardAndDicVo, auditStatus, null);
    }

    /**
     * 保持原有逻辑，该方法的{@link DapStandardAuditVersionMain#getModifyType()}只能设置为1/2（新增、修改）没有删除
     * 没有删除是由于初期开发删除，不走流程
     * 调整时间为2020年10月13日
     */
    private String saveOrUpdateStandardAndAudit(BasePublishInfoOfStandard<?> abstractstandard,
                                                StandardAuditStatus auditStatus,
                                                String standardId) {
        return saveOrUpdateStandardAndAudit(abstractstandard, auditStatus, standardId, null);
    }

    /**
     * 针对标准（基础、指标）进行结合流程新增或编辑数据
     * 2020年9月7日09:52:26
     * 增加指标关联【其他】指标的逻辑，在已发布版本进行编辑启动新的指标标准流程时，
     * 需要判断新增的关联指标id是否为当前指标的id，若是则不允许进行新增
     *
     * @param abstractstandard BasicStandardAndDicVo | IndexStandardVo
     * @param standardId       编辑标准id
     * @return 标准id
     * @since 2020年10月13日，增加变更类型为3（删除）的逻辑
     */
    private String saveOrUpdateStandardAndAudit(BasePublishInfoOfStandard<?> abstractstandard,
                                                StandardAuditStatus auditStatus,
                                                String standardId,
                                                Integer modifyType) {
        // 新增
        Integer standardType = null;
        String standardIdNew = null;
        // 新增 (默认为1 新增）根据标准ID是否存在来判断是新增还是修改，而删除则根据入参modifyType=3来确定，若是null则设置为1
        int auditModifyType = 1;
        modifyType = (modifyType == null) ? 1 : modifyType;
        if (StringUtils.isBlank(standardId)) {
            // 新增的时候标准的standardUniqueId为空，只有增加到审批流程中才会有值，所以在查询数据库中需要注意是否为空
            if (abstractstandard instanceof BasicStandardAndDicVo) {
                BasicStandardAndDicVo basicStandardAndDicVo = (BasicStandardAndDicVo) abstractstandard;
                standardType = 0;
                Optional<String> standardIdOpt = saveStandardBasicAndDic(basicStandardAndDicVo);
                standardIdNew = standardIdOpt.orElseThrow(() -> new DapException("保存数据标准失败"));
            } else if (abstractstandard instanceof DapStandardIndex) {
                DapStandardIndex indexStandardVo = (DapStandardIndex) abstractstandard;
                standardType = 1;
                DapStandardIndex standardIndex = dapStandardIndexService.checkAndSaveOrUpdate(indexStandardVo);
                standardIdNew = standardIndex.getId();
            }
            if (standardIdNew != null && standardType != null) {
                auditVersionMainService.auditChangeByStandardId(standardIdNew, standardType, auditStatus, auditModifyType, null);
            } else {
                log.warn("系统写入标准数据失败");
            }
        } else { // 编辑 调整：变更类型增加删除逻辑
            auditModifyType = (modifyType == 3) ? 3 : 2;
            standardIdNew = standardId;
            if (abstractstandard instanceof BasicStandardAndDicVo) {
                DapStandardBasic basicServiceById = dapStandardBasicService.getById(standardId);
                standardType = 0;
                BmAssetUtils.notNull(basicServiceById, "获取原标准数据为空");
                BasicStandardAndDicVo basicStandardAndDicVo = (BasicStandardAndDicVo) abstractstandard;
                // 已发布
                // 增加前置判断，若流程中已存在待发布数据，则不进行【新增版本+新增标准数据】
                if (Boolean.TRUE.equals(basicServiceById.getPublishNewest()) && auditIsAllPublished(basicServiceById)) {
                    basicStandardAndDicVo.setId(null);
                    basicStandardAndDicVo.setPublishNewest(null);
                    basicStandardAndDicVo.setPublishTime(null);
                    basicStandardAndDicVo.setStandardUniqueId(basicServiceById.getStandardUniqueId());
                    dapStandardBasicService.checkAndThenSaveOrUpdate(basicStandardAndDicVo);
                    basicStandardAndDicVo.getDapStandardBasicDics().forEach(d -> {
                        d.setId(null);
                        d.setBasicStandardId(basicStandardAndDicVo.getId());
                    });
                    String nextStandardId = basicStandardAndDicVo.getId();
                    dapStandardBasicDicService.mySaveOrUpdateBatch(basicStandardAndDicVo, basicStandardAndDicVo.getDapStandardBasicDics(), nextStandardId);
                    log.info("变更 + 已发布 => 新增版本+新增标准数据，保存数据情况： id:{}", nextStandardId);
                    auditVersionMainService.auditChangeByStandardId(standardId, standardType, StandardAuditStatus.草稿, auditModifyType, nextStandardId);
                    // 最新标准id
                    standardIdNew = nextStandardId;
                } else {
                    basicStandardAndDicVo.setId(standardId);
                    basicStandardAndDicVo.setStandardUniqueId(basicServiceById.getStandardUniqueId());
                    dapStandardBasicService.checkAndThenSaveOrUpdate(basicStandardAndDicVo);
                    dapStandardBasicDicService.mySaveOrUpdateBatch(basicStandardAndDicVo, basicStandardAndDicVo.getDapStandardBasicDics(), standardId);
                    auditVersionMainService.auditChangeByStandardId(standardId, standardType, auditStatus, auditModifyType, null);
                    log.info("变更 + !已发布 => 版本不变+修改当前版本对应的标准数据，, id:{}", standardId);
                }
            } else if (abstractstandard instanceof IndexStandardVo ||
                    abstractstandard instanceof DapStandardIndex) {
                DapStandardIndex standardIndex = dapStandardIndexService.getById(standardId);
                BmAssetUtils.notNull(standardIndex, "获取指标数据失败");
                DapStandardIndex indexStandardVo = (DapStandardIndex) abstractstandard;
                // 已发布
                // 增加前置判断，若流程中已存在待发布数据，则不进行【新增版本+新增标准数据】
                if (Boolean.TRUE.equals(standardIndex.getPublishNewest()) && auditIsAllPublished(standardIndex)) {
                    indexStandardVo.setId(null);
                    indexStandardVo.setPublishNewest(null);
                    indexStandardVo.setPublishTime(null);
                    indexStandardVo.setStandardUniqueId(standardIndex.getStandardUniqueId());
                    // 前置判断 在已发布版本进行编辑启动新的指标标准流程时，
                    // 需要判断新增的关联指标id是否为当前指标的id，若是则不允许进行新增
                    String[] relateIndexes = StringUtils.trimToEmpty(indexStandardVo.getRelatedIndex()).split(",");
                    boolean matchSelf = Arrays.stream(relateIndexes).anyMatch(id -> standardIndex.getStandardUniqueId().equals(id));
                    BmAssetUtils.isFalse(matchSelf, "启动新版本数据中，【关联指标中】不允许关联自己版本的指标");
                    DapStandardIndex saveOrUpdate = dapStandardIndexService.checkAndSaveOrUpdate(indexStandardVo);
                    String nextStandardId = saveOrUpdate.getId();
                    log.info("变更 + 已发布 => 新增版本+新增标准数据，保存数据情况： id:{}", nextStandardId);
                    auditVersionMainService.auditChangeByStandardId(standardId, standardType, StandardAuditStatus.草稿, auditModifyType, nextStandardId);
                    // 最新标准id
                    standardIdNew = nextStandardId;
                } else {
                    indexStandardVo.setId(standardId);
                    indexStandardVo.setStandardUniqueId(standardIndex.getStandardUniqueId());
                    dapStandardIndexService.checkAndSaveOrUpdate(indexStandardVo);
                    auditVersionMainService.auditChangeByStandardId(standardId, standardType, auditStatus, auditModifyType, null);
                    log.info("变更 + !已发布 => 版本不变+修改当前版本对应的标准数据，, id:{}", standardId);
                }
            }
        }
        return standardIdNew;
    }

    /**
     * 判断当前标准是否都处于已发布状态
     *
     * @param std 标准抽象类
     * @return true 都处于已发布
     */
    @Override
    public boolean auditIsAllPublished(BasePublishInfoOfStandard<?> std) {
        if (std == null) {
            return true;
        }
        String standardUniqueId = std.getStandardUniqueId();
        List<DapStandardAuditVersionMain> auditVersionMains = auditVersionMainService.findByStandardUniqueId(standardUniqueId);
        return auditVersionMains.stream().allMatch(d -> StandardAuditStatus.已发布.equals(d.getAuditStatus()));
    }

    @Override
    public BasicStandardAndDicVo getBasicStandardAndDicVo(String standardId) {
        DapStandardBasic standardBasic = dapStandardBasicService.getByIdAsset(standardId, "获取基础标准数据为空，请刷新重试");
        BasicStandardAndDicVo basicStandardAndDicVo = new BasicStandardAndDicVo(standardBasic);
        LambdaQueryWrapper<DapStandardBasicDic> eq = Wrappers.lambdaQuery(new DapStandardBasicDic())
                .eq(DapStandardBasicDic::getBasicStandardId, standardId)
                .eq(DapStandardBasicDic::getBmStatus, BmStatus.ON);
        List<DapStandardBasicDic> dapStandardBasicDics = dapStandardBasicDicService.list(eq);
        basicStandardAndDicVo.setDapStandardBasicDics(dapStandardBasicDics);
        return basicStandardAndDicVo;
    }

    @Override
    public String editBasicStandardAndDicAndAudit(BasicStandardAndDicVo basicStandardAndDicVo, String standardId) {
        return saveOrUpdateStandardAndAudit(basicStandardAndDicVo, null, standardId);
    }

    @Override
    public IPage<StandardDataModifyVo> modifyList(StandardListSearchVo<?> standardListSearchVo) {
        // select * from t_audit where standard_type=1 group by statu
        return Boolean.FALSE.equals(standardListSearchVo.getTreePage()) ?
                auditVersionMainService.modifyOrAuditListOfStandard(standardListSearchVo, Boolean.FALSE) :
                auditVersionMainService.modifyOrAuditLogicPageOfStandard(standardListSearchVo, Boolean.FALSE);
    }

    @Override
    public void startAudit(String... ids) {
        // 判断id是否需要待审批（是否为草稿或者不通过）
        if (ids != null) {
            Arrays.stream(ids).forEach(id -> {
                DapStandardAuditVersionMain versionMain = auditVersionMainService.getByIdAsset(id, "获取流程信息失败");
                BmAssetUtils.isTrue(StandardAuditStatus.草稿.equals(versionMain.getAuditStatus()) || StandardAuditStatus.不通过.equals(versionMain.getAuditStatus()), "只允许不通过或者草稿进行发起审批");
                auditVersionMainService.auditChangeStatusByAuditId(id, StandardAuditStatus.待审批, null);
            });
        }
    }

    @Override
    public String editIndexStandardAndAudit(DapStandardIndex dapStandardIndex, String standardIndexId) {
        return saveOrUpdateStandardAndAudit(dapStandardIndex, null, standardIndexId);
    }

    @Override
    public String saveStandardIndexAndAudit(DapStandardIndex dapStandardIndex) {
        return saveOrUpdateStandardAndAudit(dapStandardIndex, null, null);
    }

    /**
     * 针对导入中，指定标准的初始化审核状态
     */
    @Override
    @Transactional
    public String saveStandardIndexAndAudit(DapStandardIndex dapStandardIndex, StandardAuditStatus auditStatus) {
        return saveOrUpdateStandardAndAudit(dapStandardIndex, auditStatus, null);
    }

    /**
     * 流程id来
     * 撤销流程（待审批->不通过）
     *
     * @since v1.1 2020年9月9日09:53:35
     * 经过昨天会议，明确了撤销动作不是针对待审批状态数据进行撤销，而是对草稿状态的数据进行撤销
     * （可以理解为把流程中的新版本进行删除）
     */
    @Override
    public void revertAudit(String auditId) {
        auditVersionMainService.auditChangeStatusByAuditId(auditId, StandardAuditStatus.撤销, null);
    }

    /**
     * 针对文件路径进行读取导入
     * 变更内容：{@link DapConstant.VersionMark}
     */
    @Override
    public ResultBean<?> fileImport(String filePath, Integer standardType) {
        ResultBean<?> resultBean;
        if (standardType == 0) {
            resultBean = importBasicStandardExcel(filePath);
        } else {
            resultBean = importIndexStandardExcel(filePath);
        }
        return resultBean;
    }

    @Override
    public Optional<String> storeUploadFile(MultipartFile file, String originalFilename) {
        Optional<String> storePathSaveOpt = bmDapConfig.standardStorePathOpt(originalFilename);
        storePathSaveOpt.ifPresent(storePath -> {
            try {
                File saveFile = new File(storePath);
//                    Files.createParentDirs(saveFile);
                if (!saveFile.exists()) {
                    boolean mkdirs = saveFile.getParentFile().mkdirs();
                    log.info("首次创建{}目录{}，保存时长：{}", mkdirs, saveFile.getAbsolutePath(), bmDapConfig.getFile().getTtl());
                    Files.createFile(saveFile.toPath());
                }
                try (InputStream inputStream = file.getInputStream()) {
                    Files.copy(inputStream, saveFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
        return storePathSaveOpt;
    }

    /**
     * 根据 standardType 区分导入类型
     * 支持导入基础和指标
     *
     * @since 2020年9月10日17:10:16 在线会议确定，导入excel数据标准中导入的数据状态从之前的【待审批】调整为【草稿】
     * 变更内容：{@link DapConstant.VersionMark}STANDARD_EXCEL_IMPORT
     */
    @Override
    public ResultBean<?> fileImport(InputStream inputStream,
                                    MultipartFile file,
                                    Integer standardType) {
        String originalFilename = file.getOriginalFilename();
        BmAssetUtils.isTrue(StringUtils.isNotBlank(originalFilename), "获取上传文件名为空！");
        String fileSuffix = originalFilename.substring(originalFilename.lastIndexOf("."));
        ResultBean<?> resultBean = ResultBean.FAIL;
        Path tempFile = null;
        try {
            Path tmpDir = Paths.get(bmDapConfig.getFile().getSaveFileTempDir());
            if (Files.notExists(tmpDir)) {
                Files.createDirectories(tmpDir);
            }
            String fileTempPath = bmDapConfig.getFile().getSaveFileTempDir() + "/" + IdWorker.get32UUID() + fileSuffix;
            tempFile = Paths.get(fileTempPath);
            Files.createFile(tempFile);
            Files.copy(inputStream, tempFile, StandardCopyOption.REPLACE_EXISTING);
            if (standardType == 0) {
                resultBean = importBasicStandardExcel(fileTempPath);
            } else {
                resultBean = importIndexStandardExcel(fileTempPath);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (tempFile != null) {
                    Files.deleteIfExists(tempFile);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return resultBean;
    }

    /**
     * 导入指标标准的Excel数据
     *
     * @since 2020年9月10日17:10:16 在线会议确定，导入excel数据标准中导入的数据状态从之前的【待审批】调整为【草稿】
     * @since 2020年9月29日16:25:56 测试评审讨论，增加条件，<em>必须文件全部通过校验</em>才可以入库
     */
    @Override
    public ResultBean<?> importIndexStandardExcel(String filePath) {
        // init
        List<DapSystemCategory> systemTopics = dapSystemCategoryService.findTopicsByLevel(0);
        List<DapSystemCategory> systemCategories = dapSystemCategoryService.systemTopicAndCategories("0");
        Map<String, String> dbDistinctDepartAndIdMap = systemDepartmentService.dbDistinctDepartAndIdMap();
        Tuple2<Set<String>, Set<String>> tuple2_ = dapStandardIndexService.dbPublishStandardNameAndEngName();
        Map<String, String> nameAndStdUniqueIds = dapStandardIndexService.dbPublishStandardNameAndStdUniqueIds();
        List<BizLineResponseVo> bizLines = dapSystemModuleFacade.listBizLines();
        Map<String, Integer> bizLineNameAndIds = bizLines.stream().collect(Collectors.toMap(BizLineResponseVo::getCodeName, BizLineResponseVo::getBizLineId, (a, b) -> b));
        List<DapStandardDim> dims = dimService.list(dimService.bmLambdaQuery().select(DapStandardDim::getCodeName, DapStandardDim::getId));
        Map<String, String> dimNameAndIds = dims.stream().collect(Collectors.toMap(DapStandardDim::getCodeName, DapStandardDim::getId));
        ResultBean<List<DapSystemInfo>> sysInfosRt = systemInfoService.getSysInfos(null);
        BmAssetUtils.isTrue(sysInfosRt.isOk(), sysInfosRt.getMsg());
        List<DapSystemInfo> systemInfos = sysInfosRt.getContent();
        Map<String, String> dbSysInfoMap = systemInfos.stream().collect(Collectors.toMap(DapSystemInfo::getName, DapSystemInfo::getId, (a, b) -> a));
        // main
        try (IndStdImportVerifyHandler verifyHandler = new IndStdImportVerifyHandler(systemTopics, systemCategories, dbDistinctDepartAndIdMap,
                tuple2_.getT1(), tuple2_.getT2())) {
            verifyHandler.setDimNameAndIdMap(dimNameAndIds);
            verifyHandler.setBizLineAndIdMap(bizLineNameAndIds);
            verifyHandler.setDbPublishedStandardNameAndStdUnqueIds(nameAndStdUniqueIds);
            verifyHandler.setDbDataSourceSystemMap(dbSysInfoMap);
            Map<String, String> models = modelModuleFacade.queryAllDataWarehouseModelInfos().stream().collect(Collectors.toMap(DapModelModuleFacade.ModelInfo::getModelName, DapModelModuleFacade.ModelInfo::getModelId, (a, b) -> b));
            verifyHandler.setModelNameAndIdMap(models);
            verifyHandler.setModelModuleFacade(modelModuleFacade);
            ImportParams params = new ImportParams();
            params.setHeadRows(2);
            params.setNeedVerify(true);
            params.setVerifyGroup(new Class[]{ExcelImportGroup.class});
            params.setVerifyHandler(verifyHandler);
            ExcelImportResult<IndexStandardVo> result = ExcelImportUtil.importExcelMore(
                    new File(filePath),
                    IndexStandardVo.class, params);
            List<IndexStandardVo> list = result.getList();
            // 增加条件，必须文件全部通过校验才可以入库
            List<IndexStandardVo> failList = result.getFailList();
            if (!failList.isEmpty()) {
                String error = ExcelImportResultUtils.generateSheetErrorInfoByFailList(failList);
                log.error("获取导入标准中错误数据:{}", failList);
                // 定义为ok,属于可预知错误信息
                return ResultBean.ok(failList).setMsg(error);
            }
            for (IndexStandardVo obj : list) {
                saveStandardIndexAndAudit(obj, StandardAuditStatus.草稿);
                relateStandardAndModel(obj);
            }
            return ResultBean.ok("写入标准数据" + list.size() + "条");
        }
    }

    private void relateStandardAndModel(IndexStandardVo obj) {
        // 数仓模型名、模型表及其字段关系建立
        IndexStandardRelateDwModelVo relateDwModelVo = obj.getIndexStandardRelateDwModelVo();
        if (relateDwModelVo != null) {
            relateDwModelVo.setStandardId(obj.getId());
            standardIndexService.relateDwModelTableInfo(relateDwModelVo);
        }
    }

    @Deprecated
    private Optional<IndexStandardRelateDwModelVo> relateStandardAndModel(String standardId, String dwModelName, String dwTableField) {
        if (StringUtils.isBlank(dwModelName) || StringUtils.isBlank(dwTableField) || !dwTableField.contains(".")) {
            return Optional.empty();
        }
        Optional<DapModelModuleFacade.ModelInfo> modelInfos = modelModuleFacade.queryOneDataWarehouseModelInfo(dwModelName);
        log.info("标准id{}与模型{}的关系，{}", standardId, dwModelName, modelInfos.orElse(null));
        Optional<IndexStandardRelateDwModelVo> res = modelInfos.map(modelInfo -> {
            IndexStandardRelateDwModelVo relateDwModelVo = new IndexStandardRelateDwModelVo();
            relateDwModelVo.setStandardId(standardId);
            relateDwModelVo.setDwModelId(modelInfo.getModelId());
            // 根据模型id+表英文名+字段英文名=>表和字段id
            String[] tableNameAndFieldName = dwTableField.split("\\.");
            final String tableName = tableNameAndFieldName[0], fieldName = tableNameAndFieldName[1];
            Optional<Tuple2<String, String>> tableIdAndFieldId = modelModuleFacade.queryTableAndField(modelInfo.getModelId(), tableName, fieldName);
            return tableIdAndFieldId.map(tf -> {
                log.info("获取标准与模型表信息{}", tableIdAndFieldId.get());
                relateDwModelVo.setDwTableId(tf.getT1());
                relateDwModelVo.setDwTableFieldId(tf.getT2());
                return relateDwModelVo;
            }).orElse(null);
        });
        return res;
    }

    /**
     * @param filePath wenj
     * @since 2020年9月10日17:10:16 在线会议确定，导入excel数据标准中导入的数据状态从之前的【待审批】调整为【草稿】
     * @since 2020年9月29日16:25:56 测试评审讨论，增加条件，<em>必须文件全部通过校验</em>才可以入库
     */
    @Override
    public ResultBean<?> importBasicStandardExcel(String filePath) {
        try {
            // 读取sheet
            ExcelImportResult<BasicStandardAndDicVo> bsImportResult = dapStandardBasicService.parserSheet1(filePath);
            List<BasicStandardAndDicVo> basicStandardList = bsImportResult.getList();
            ExcelImportResult<BasicStandardAndDicMiddleVo> bsAndDicMidEImportResult = dapStandardBasicService.parserSheet2(filePath);
            ExcelImportResult<DapStandardBasicDic> bsDicEImportResult = dapStandardBasicService.parserSheet3(filePath);
            // 增加条件，必须文件全部通过校验才可以入库
            boolean hadFail = Arrays.asList(!bsImportResult.getFailList().isEmpty(), !bsAndDicMidEImportResult.getFailList().isEmpty(), !bsDicEImportResult.getFailList().isEmpty()).contains(Boolean.TRUE);
            if (hadFail) {
                return resultOf(bsImportResult, bsAndDicMidEImportResult, bsDicEImportResult);
            }
            // 根据 baseCode 从sheet2中获取 baseCodeName 回填，多个sheet中需要互相翻译/关联
            Map<String, Object> baseCodeAndNameMap = bsAndDicMidEImportResult.getMap();
            Map<String, List<DapStandardBasicDic>> collectGroupByCode = bsDicEImportResult.getList().stream()
                    // 根据sheet2中进行翻译获取baseCodeName如果依旧为空，则赋值baseCode
                    .peek(vo -> {
                        if (baseCodeAndNameMap != null) {
                            vo.setDataSourceFromExcel(Boolean.TRUE);
                            Object tuple2 = baseCodeAndNameMap.get(vo.getBaseCode());
                            if (tuple2 instanceof Tuple2) {
                                //noinspection rawtypes
                                vo.setBaseCodeName(Objects.toString(((Tuple2) tuple2).getT1(), vo.getBaseCode()));
                                //noinspection rawtypes
                                vo.setBaseRemark(Objects.toString(((Tuple2) tuple2).getT2(), null));
                            } else {
                                vo.setBaseCodeName(Objects.toString(tuple2, vo.getBaseCode()));
                            }
                        }
                    })
                    .collect(Collectors.groupingBy(DapStandardBasicDic::getBaseCode));
            // 建立代码类的标准与代码集关系，发现存在无法对应的编码级校验
            List<BasicStandardAndDicVo> joinCodeErrors = Lists.newArrayList();
            basicStandardList.stream()
                    .filter(Objects::nonNull)
                    .forEach(vo -> {
                        if (StandardDataType.代码类.equals(vo.getDataType()) && StringUtils.isNotBlank(vo.getSourceCode())) {
                            List<DapStandardBasicDic> basicStandardDicVos = collectGroupByCode.getOrDefault(vo.getSourceCode(), Collections.emptyList());
                            // 去掉errormsg not null
                            if (basicStandardDicVos.isEmpty()) {
                                vo.setErrorMsg(StrFormatter.format("第{}行[引用代码]获取sheet[{}]的代码字典为空", vo.getRowNum() + 1, DapConstant.DapStandard.STANDARD_IMPORT_FILE_SHEET3_NAME));
                                joinCodeErrors.add(vo);
                            } else {
                                vo.setDapStandardBasicDics(basicStandardDicVos);
                            }
                        }
                    });
            if (!joinCodeErrors.isEmpty()) {
                bsImportResult.setFailList(joinCodeErrors);
                return resultOf(bsImportResult, null, null);
            }
            log.info("开始导入数据标准条数：{}", basicStandardList.size());
            // 入库
            insertBasicStandardDb(collectGroupByCode, basicStandardList);
            // 结果返回
            return resultOf(bsImportResult, bsAndDicMidEImportResult, bsDicEImportResult);
        } catch (Exception e) {
            e.printStackTrace();
            throw new DapThrowException(e.getMessage());
        }
    }

    /**
     * 入库 基础标准
     *
     * @since 2020年9月10日17:10:16 在线会议确定，导入excel数据标准中导入的数据状态从之前的【待审批】调整为【草稿】
     */
    private void insertBasicStandardDb(Map<String, List<DapStandardBasicDic>> collectGroupByCode,
                                       List<BasicStandardAndDicVo> basicStandardList) {
        if (!basicStandardList.isEmpty()) {
            basicStandardList.parallelStream()
                    .filter(Objects::nonNull)
                    .forEach(vo -> saveStandardBasicAndDicAndAudit(vo, StandardAuditStatus.草稿));
        }
    }

    /**
     * 删除操作需要进行审批流程
     * <p>
     *
     * @since 2020年10月12日19:43:13 删除功能调整（期初理解为直接进行对标准删除，而今天落地确认为
     * <em>删除标准的业务逻辑是：启动一个删除的流程审批数据
     * （即变更类型为{@link DapStandardAuditVersionMain#getModifyType()} == 3以及变更状态为{@link StandardAuditStatus#草稿}的流程数据）</em>
     * 而最终是否删除标准，取决于是否通过待审批，若待审批通过则对{@link DapStandardAuditVersionMain#getModifyType()} == 3进行删除整个标准的流程数据和引用关系
     * 注意：其中{@link DapStandardAuditVersionMain#getModifyType()} == 3的流程数据是不可编辑的、
     * 并且要确保{@link DapStandardAuditVersionMain#getModifyType()} 一直为3（删除）来确保通过审批进行删除
     */
    @Override
    public void deleteAudit(String stdId, int standardType) {
        //noinspection rawtypes
        BasePublishInfoOfStandard stdBase;
        if (standardType == 0) {
            // 基础标准返回{BasicStandardAndDicVo}
            stdBase = getBasicStandardAndDicVo(stdId);
        } else {
            stdBase = dapStandardIndexService.getByIdAsset(stdId);
        }
        saveOrUpdateStandardAndAudit(stdBase, StandardAuditStatus.草稿, stdId, 3);
    }

    /**
     * @param vo 标准抽象
     * @return true 为存在变更中 数据，f 不存在
     */
    @SuppressWarnings("rawtypes")
    @Override
    public boolean analyseAuditChanging(BasePublishInfoOfStandard vo) {
        return !auditIsAllPublished(vo);
    }

    @Override
    @Transactional
    public ResultBean<?> fileImportV2(InputStream inputStream, MultipartFile file,
                                      Integer standardType, Integer bizLineId,
                                      UserInfoHolder.UserInfo userInfo) {
        String originalFilename = file.getOriginalFilename();
        BmAssetUtils.isTrue(StringUtils.isNotBlank(originalFilename), "获取上传文件名为空！");
        String fileSuffix = originalFilename.substring(originalFilename.lastIndexOf("."));
        BizLineResponseVo bizLine = dapSystemModuleFacade.getBizLineInfoById(bizLineId);
        BmAssetUtils.notNull(bizLine, "获取业务线信息失败");

        ResultBean<?> resultBean = ResultBean.FAIL;
        Path tempFile = null;
        try {
            Path tmpDir = Paths.get(bmDapConfig.getFile().getSaveFileTempDir());
            if (Files.notExists(tmpDir)) {
                Files.createDirectories(tmpDir);
            }
            String fileTempPath = bmDapConfig.getFile().getSaveFileTempDir() + "/" + IdWorker.get32UUID() + fileSuffix;
            tempFile = Paths.get(fileTempPath);
            Files.createFile(tempFile);
            Files.copy(inputStream, tempFile, StandardCopyOption.REPLACE_EXISTING);
            if (standardType == 0) {
                throw new DapException("暂不支持新版基础标准导入");
//                resultBean = importBasicStandardExcel(fileTempPath);
            } else {
                resultBean = importIndexStandardExcelV2(fileTempPath, bizLineId, userInfo);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (tempFile != null) {
                    Files.deleteIfExists(tempFile);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return resultBean;
    }

    private ResultBean<?> importIndexStandardExcelV2(String filePath, Integer bizLineId, UserInfoHolder.UserInfo userInfo) throws IOException {
        FileInputStream inputStream = new FileInputStream(filePath);
        List<IndexStandardDataVo> indexData = readIndexExcel(inputStream);
        if (indexData.isEmpty()) {
            return ResultBean.error("文件指标为空，导入失败！");
        }
        List<String> errors = doValidate(indexData, bizLineId);
        if (!errors.isEmpty()) {
            return ResultBean.error("导入失败！", errors);
        }
        List<DapStandardIndex> dapStandardIndices = toDapStandardIndex(indexData, bizLineId, userInfo.getAccount());
        for (DapStandardIndex each : dapStandardIndices) {
            saveStandardIndexAndAudit(each, StandardAuditStatus.草稿);
        }
//        standardIndexService.saveBatch(dapStandardIndices);
        return ResultBean.ok("导入成功！");
    }

    private List<DapStandardIndex> toDapStandardIndex(List<IndexStandardDataVo> indexData, Integer bizLineId, String createdBy) {
        List<DapStandardIndex> indices = new ArrayList<>();
        for (IndexStandardDataVo each : indexData) {
            DapStandardIndex index = new DapStandardIndex();
            String indexId = null;
            index.setId(indexId);
            index.setDataSourceSystem(each.getDataSourceSystem());
            index.setAccessLogic(each.getAccessLogic());
            index.setDataWarehouseMakeLogic("");
            index.setDataWarehouseModel(each.getDataWarehouseModelTable());
//            index.setDataWarehouseModelName("");
            index.setIndexFormat(each.getIndexDataTypeEnum());
            index.setCommonUnits(each.getUnit());
            index.setDataAccuracy(each.getPrecision());
            index.setIndexType(each.getIndexTypeInteger());
            index.setRelatedIndex(each.getRelateIndexIds());
            index.setAssociationDimension(each.getRelateDimNames());
            index.setValueRange(each.getValueRange());
            index.setBusinessPersonnel(each.getBizPerson());
            index.setDataAnalyst(each.getDataAnalyst());
            index.setDataWarehouseDeveloper(each.getDataWarehouseDeveloper());
            index.setBusinessDefinition(each.getBizDefine());
            index.setCalculationFormula(each.getCalcRule());
//            index.setDateLength("");
            index.setFormulationBasis(ReferRulesType.COMPANY_STD);
            index.setIndexChinName(each.getIndexName());
            String indexCode = sequenceGenerateService.getSeqByTypeAndTopicId("ZB", each.getTopicId());
            index.setIndexCode(indexCode);
            index.setIndexEngName(StringUtils.isBlank(each.getIndexEngName()) ? indexCode : each.getIndexEngName());
            index.setIndexUsage(each.getIndexUsage());
            index.setManagementDepartmentId(each.getManageDeptId());
            index.setPrimarySort(each.getCategory1Id());
            index.setSecondarySort(each.getCategory2Id());
            index.setTheme(each.getTopicId());
            index.setThirdSort(each.getCategory3Id());
            index.setBizLineId(bizLineId);
            index.setIndexSimpleName(each.getIndexSimpleName());
            index.setDataParticleSize(each.getDataParticleSize());
            index.setManagePerson(each.getManagePerson());
            index.setDemandDept(each.getDemandDeptId());
            index.setModifyReason(each.getModifyReason());
            index.setProposeTime(each.getProposeTime());
//            index.setIndexAppName("");
//            index.setIndexBizDesc("");
            index.setStandardUniqueId(indexId);
            index.setPublishNewest(false);
            index.setCreateBy(createdBy);
            index.setCreateTime(LocalDateTime.now());
            index.setBmStatus(BmStatus.ON);
            indices.add(index);
        }
        return indices;
    }

    private List<String> doValidate(List<IndexStandardDataVo> indexData, Integer bizLineId) {
        List<String> errors = new ArrayList<>();
        Map<String, DapSystemCategory> topicNameAndPo = dapSystemCategoryService.findTopicsByLevel(0).stream().collect(Collectors.toMap(DapSystemCategory::getCodeName, d -> d));
        Map<String, List<DapSystemCategory>> pidAndCategory1 = dapSystemCategoryService.getTopicsAndCategories().get("category1");
        Map<String, List<DapSystemCategory>> pidAndCategory2 = dapSystemCategoryService.getTopicsAndCategories().get("category2");
        Map<String, List<DapSystemCategory>> pidAndCategory3 = dapSystemCategoryService.getTopicsAndCategories().get("category3");
//        Map<String, List<DapSystemCategory>> categoryPidAndPo = dapSystemCategoryService.systemTopicAndCategories("0").stream().collect(Collectors.groupingBy(DapSystemCategory::getParentId));

        Map<String, Integer> indexTypeMap = new HashMap<String, Integer>() {{
            put("原子指标", 1);
            put("派生指标", 2);
            put("计算指标", 3);
            put("维度（属性）", 4);
            put("维度(属性)", 4);
        }};
        Map<String, StandardDataType> stdDataTypeMap = new HashMap<String, StandardDataType>() {{
            put("金额类", StandardDataType.金额类);
            put("数值类", StandardDataType.数值类);
        }};
//        Map<String, StandardDataType> stdDataTypeMap = Arrays.stream(StandardDataType.values()).collect(Collectors.toMap(s -> s.name(), s));
//        Map<String, Integer> wechatDeptAndIdMap = getWechatDept();
        Map<String, String> systemDeptAndIdMap = systemDepartmentService.dbDistinctDepartAndIdMap();

        Map<String, String> nameAndStdUniqueIds = dapStandardIndexService.list(Wrappers.<DapStandardIndex>lambdaQuery().eq(DapStandardIndex::getBmStatus, BmStatus.ON)
                .eq(DapStandardIndex::getBizLineId, bizLineId)).stream().collect(Collectors.toMap(DapStandardIndex::getIndexChinName, DapStandardIndex::getStandardUniqueId, (a, b) -> b));

//        维度关系调整走名称进行维度关联（原因是维度可以没维护，也能导入）
//        Map<String, String> dimNameAndIds = dimService.list(dimService.bmLambdaQuery().select(DapStandardDim::getCodeName, DapStandardDim::getId)).stream().collect(Collectors.toMap(DapStandardDim::getCodeName, DapStandardDim::getId));
        // 根据导入的数仓模型表(表名.字段)获取hive中表名、技术口径(ETL名)、ETL开发最新人员 // TODO: 2022/12/15 理可提供接口

        final Field[] fields = IndexStandardDataVo.class.getDeclaredFields();
        for (IndexStandardDataVo index : indexData) {
            int rowIndex = index.getRowIndex();
            // 非空、长度、数据合法性等校验
            for (Field field : fields) {
                if (field.getAnnotation(ExcelProperty.class) != null) {
                    final String value = getValueByReflect(index, field);
                    ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class);
                    if (!excelProperty.nullable()) {
                        if (StringUtils.isBlank(value)) {
                            errors.add(String.format("第%d行第%s列[%s]不可为空", rowIndex + 1, excelProperty.index() + 1, excelProperty.name()));
                        }
                    }
                    if (excelProperty.size() != -1) {
                        if (StringUtils.isNotBlank(value) && value.length() > excelProperty.size()) {
                            errors.add(String.format("第%d行第%s列[%s]长度不大于%d", rowIndex + 1, excelProperty.index() + 1, excelProperty.name(), excelProperty.size()));
                        }
                    }
                    // 关系、数据合法性校验
                    if (excelProperty.name().equalsIgnoreCase("*主题")) {
                        if (StringUtils.isNotBlank(value)) {
                            if (!topicNameAndPo.containsKey(value)) {
                                errors.add(String.format("第%d行第%s列[%s]数据不合法", rowIndex + 1, excelProperty.index() + 1, excelProperty.name()));
                            } else {
                                index.setTopicId(topicNameAndPo.get(value).getId());
                            }
                        }
                    }
                    if (excelProperty.name().equalsIgnoreCase("*一级分类")) {
                        if (StringUtils.isNotBlank(value) && StringUtils.isNotBlank(index.getTopicId())) {
                            String topicId = index.getTopicId();
                            List<DapSystemCategory> category = pidAndCategory1.getOrDefault(topicId, Collections.emptyList());
                            String categoryId = category.stream().filter(c -> c.getCodeName().equalsIgnoreCase(value)).findFirst().map(DapSystemCategory::getId).orElse(null);
                            if (StringUtils.isBlank(categoryId)) {
                                errors.add(String.format("第%d行第%s列[%s]数据不合法", rowIndex + 1, excelProperty.index() + 1, excelProperty.name()));
                            } else {
                                index.setCategory1Id(categoryId);
                            }
                        }
                    }
                    if (excelProperty.name().equalsIgnoreCase("二级分类")) {
                        if (StringUtils.isNotBlank(value) && StringUtils.isNotBlank(index.getCategory1Id())) {
                            List<DapSystemCategory> category = pidAndCategory2.getOrDefault(index.getCategory1Id(), Collections.emptyList());
                            String categoryId = category.stream().filter(c -> c.getCodeName().equalsIgnoreCase(value)).findFirst().map(DapSystemCategory::getId).orElse(null);
                            if (StringUtils.isBlank(categoryId)) {
                                errors.add(String.format("第%d行第%s列[%s]数据不合法", rowIndex + 1, excelProperty.index() + 1, excelProperty.name()));
                            } else {
                                index.setCategory2Id(categoryId);
                            }
                        }
                    }
                    if (excelProperty.name().equalsIgnoreCase("三级分类")) {
                        if (StringUtils.isNotBlank(value) && StringUtils.isNotBlank(index.getCategory2Id())) {
                            List<DapSystemCategory> category = pidAndCategory3.getOrDefault(index.getCategory2Id(), Collections.emptyList());
                            String categoryId = category.stream().filter(c -> c.getCodeName().equalsIgnoreCase(value)).findFirst().map(DapSystemCategory::getId).orElse(null);
                            if (StringUtils.isBlank(categoryId)) {
                                errors.add(String.format("第%d行第%s列[%s]数据不合法", rowIndex + 1, excelProperty.index() + 1, excelProperty.name()));
                            } else {
                                index.setCategory3Id(categoryId);
                            }
                        }
                    }

                    if (excelProperty.name().equalsIgnoreCase("*归口管理部门")) {
                        if (StringUtils.isNotBlank(value)) {
                            if (!systemDeptAndIdMap.containsKey(value)) {
                                errors.add(String.format("第%d行第%s列[%s]数据不合法", rowIndex + 1, excelProperty.index() + 1, excelProperty.name()));
                            } else {
                                index.setManageDeptId(systemDeptAndIdMap.get(value) + "");
                            }
                        }
                    }
                    if (excelProperty.name().equalsIgnoreCase("*需求部门")) {
                        if (StringUtils.isNotBlank(value)) {
                            if (!systemDeptAndIdMap.containsKey(value)) {
                                errors.add(String.format("第%d行第%s列[%s]数据不合法", rowIndex + 1, excelProperty.index() + 1, excelProperty.name()));
                            } else {
                                index.setDemandDeptId(systemDeptAndIdMap.get(value) + "");
                            }
                        }
                    }
                    if (excelProperty.name().equalsIgnoreCase("*指标类型") && StringUtils.isNotBlank(value)) {
                        if (!indexTypeMap.containsKey(value)) {
                            errors.add(String.format("第%d行第%s列[%s]数据不合法", rowIndex + 1, excelProperty.index() + 1, excelProperty.name()));
                        } else {
                            index.setIndexTypeInteger(indexTypeMap.get(value));
                        }
                    }
                    if (excelProperty.name().equalsIgnoreCase("*指标数据格式") && StringUtils.isNotBlank(value)) {
                        if (!stdDataTypeMap.containsKey(value)) {
                            errors.add(String.format("第%d行第%s列[%s]数据不合法", rowIndex + 1, excelProperty.index() + 1, excelProperty.name()));
                        } else {
                            index.setIndexDataTypeEnum(stdDataTypeMap.get(value));
                        }
                    }
                    if (excelProperty.name().equalsIgnoreCase("关联维度")) {
                        if (StringUtils.isNotBlank(value)) {
                            index.setRelateDimNames(Arrays.stream(value.split("\\|")).map(String::trim).collect(Collectors.joining(",")));
                        }
                    }
                    if (excelProperty.name().equalsIgnoreCase("关联指标")) {
                        if (StringUtils.isNotBlank(value)) {
                            if (!Arrays.stream(value.split("\\|")).map(String::trim).allMatch(v -> nameAndStdUniqueIds.containsKey(v))) {
                                errors.add(String.format("第%d行第%s列[%s]数据不合法", rowIndex + 1, excelProperty.index() + 1, excelProperty.name()));
                            } else {
                                index.setRelateIndexIds(Arrays.stream(value.split("\\|")).map(String::trim).map(v -> nameAndStdUniqueIds.get(v)).collect(Collectors.joining(",")));
                            }
                        }
                    }
                    // TODO: 2022/12/15  元数据获取
                    // 数仓模型表guid
                    // 数仓开发人员
                    // 英文名称
                    // 数仓模型名称（表注释）
                    // 技术口径
                    if (excelProperty.name().equalsIgnoreCase("数仓模型表")){
                        if (StringUtils.isNotBlank(value)){
                            index.setIndexEngName(value);
                        }
                    }
                }
            }
        }
        return errors;
    }

    private String getValueByReflect(IndexStandardDataVo index, Field field) {
        String _value = null;
        try {
            field.setAccessible(true);
            _value = (String) field.get(index);
        } catch (IllegalAccessException e) {
            log.error("反射获取字段值失败", e);
        }
        return StringUtils.trim(_value);
    }

    private Map<String, Integer> getWechatDept() {
        Map<String, Integer> wechatDeptAndIdMap = new HashMap<>();
        try {
            ResultBean<List<DapSystemWechatDeptTreeVo>> wechatDeptList = systemDepartmentService.getWechatDeptList(4);
            wechatDeptAndIdMap = wechatDeptList.getContent().stream().collect(Collectors.toMap(DapSystemWechatDeptTreeVo::getName, DapSystemWechatDeptTreeVo::getId, (a, b) -> b));
        } catch (Exception e) {
            log.error("远程获取企微部门列表失败", e);
        }
        return wechatDeptAndIdMap;
    }

    private List<IndexStandardDataVo> readIndexExcel(FileInputStream inputStream) throws IOException {
        List<IndexStandardDataVo> indexData = new ArrayList<>();
        // 全局定义
        // 0开始
        Set<Integer> cellWithoutDeleteLine = new HashSet<>();
        cellWithoutDeleteLine.add(6);// 业务定义

        // 实体反射信息
        Map<Integer, Field> reflectFieldMap = new HashMap<>();
        for (Field field : IndexStandardDataVo.class.getDeclaredFields()) {
            if (field.getAnnotation(ExcelProperty.class) != null) {
                reflectFieldMap.put(field.getAnnotation(ExcelProperty.class).index(), field);
            }
        }

        try (Workbook workbook = new XSSFWorkbook(inputStream)) {
            Sheet sheet = workbook.getSheetAt(0);
            for (int rowIndex = 0; rowIndex <= sheet.getLastRowNum(); rowIndex++) {
                // 跳过表头
                if (rowIndex < 2) {
                    continue;
                }
                Row row = sheet.getRow(rowIndex);
                IndexStandardDataVo index = new IndexStandardDataVo();
                index.setRowIndex(rowIndex);
                for (int cellIndex = 0; cellIndex < row.getLastCellNum(); cellIndex++) {
                    Cell cell = row.getCell(cellIndex);
                    String cellValue = null;
                    if (cell != null) {
                        cell.setCellType(CellType.STRING);
                        cellValue = getStringCellValue(cellWithoutDeleteLine, cellIndex, cell);
                    }
                    Field field = reflectFieldMap.get(cellIndex);
                    try {
                        field.setAccessible(true);
                        field.set(index, cellValue);
                    } catch (IllegalAccessException e) {
                        log.error("反射设置对象字段值失败！", e);
                    }
                }
                indexData.add(index);
            }
        }
        return indexData;
    }

    private String getStringCellValue(Set<Integer> cellWithoutDeleteLine, int cellIndex, Cell cell) {
        String cellValue = cell.getStringCellValue();
        if (cellWithoutDeleteLine.contains(cellIndex)) {
            // 整个单元格都是删除线的情况
            if (((XSSFCellStyle) cell.getCellStyle()).getFont().getStrikeout()) {
                cellValue = "";
            } else {
                // 部分删除线情况
                String withoutDeleteLine = getStringWithoutDeleteLine(cell);
                // withoutDeleteLine为空表示没有找到部分删除线
                if (StringUtils.isNotBlank(withoutDeleteLine)) {
                    cellValue = withoutDeleteLine;
                }
            }
        } else {
            cellValue = cell.getStringCellValue();
        }
        return cellValue;
    }

    private String getStringWithoutDeleteLine(Cell cell) {
        CTRElt[] rs = ((XSSFRichTextString) cell.getRichStringCellValue()).getCTRst().getRArray();
        if (rs.length > 0) {
            StringBuilder sb = new StringBuilder("");
            for (CTRElt r : rs) {
                if (r.getRPr() == null
                        || r.getRPr().getStrikeArray() == null
                        || r.getRPr().getStrikeArray().length == 0) {
                    sb.append(r.getT());
                } else {
                    log.info("单元格[{},{}]，发现删除线数据为：{}", cell.getRowIndex(), cell.getColumnIndex(), r.getT());
                }
            }
            // 返回刪除了消除删除线的字符串
            return sb.toString();
        }
        return "";
    }

}
